package consensus

import (
	"bytes"
	"context"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"math/big"
	"os"
	"path"
	"sort"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"github.com/spkg/zipfs"

	"github.com/caivega/glog"
	"github.com/tokentransfer/node/account"
	"github.com/tokentransfer/node/block"
	"github.com/tokentransfer/node/config"
	"github.com/tokentransfer/node/core"
	"github.com/tokentransfer/node/core/pb"
	"github.com/tokentransfer/node/crypto"
	"github.com/tokentransfer/node/merkle"
	"github.com/tokentransfer/node/service"
	"github.com/tokentransfer/node/storage"
	"github.com/tokentransfer/node/util"

	libaccount "github.com/tokentransfer/interfaces/account"
	libblock "github.com/tokentransfer/interfaces/block"
	libconsensus "github.com/tokentransfer/interfaces/consensus"
	libcore "github.com/tokentransfer/interfaces/core"
	libcrypto "github.com/tokentransfer/interfaces/crypto"
	libp2p "github.com/tokentransfer/interfaces/p2p"
	libstore "github.com/tokentransfer/interfaces/store"

	"github.com/tokentransfer/consensus/p2p"
)

var as = account.GetAccountService()
var cs = crypto.GetCryptoService()

type Node struct {
	messageId uint64

	consensusService libconsensus.ConsensusService
	p2pService       libp2p.P2PService

	entryMap    *sync.Map
	entrymap    map[string]*Entry
	entryLocker *sync.RWMutex

	transactionLocker *sync.RWMutex

	config *config.Config
	key    libaccount.Key

	self       *Peer
	indexmap   map[uint64]*Peer
	idmap      map[string]*Peer
	peerLocker *sync.RWMutex
}

func NewNode() *Node {
	ready := &sync.WaitGroup{}
	ready.Add(1)

	return &Node{
		messageId: uint64(0),

		indexmap:   make(map[uint64]*Peer),
		idmap:      make(map[string]*Peer),
		peerLocker: &sync.RWMutex{},

		transactionLocker: &sync.RWMutex{},

		entryMap:    &sync.Map{},
		entrymap:    make(map[string]*Entry),
		entryLocker: &sync.RWMutex{},
	}
}

func (n *Node) Init(c libcore.Config) error {
	n.config = c.(*config.Config)
	util.Init(n.config.GetMode())

	_, key, err := as.NewKeyFromSecret(n.config.GetSecret())
	if err != nil {
		return err
	}
	n.key = key

	pubKey, err := n.key.GetPublic()
	if err != nil {
		return err
	}
	ctx, cancel := context.WithCancel(context.Background())
	n.self = &Peer{
		Key: pubKey,

		running: true,
		ctx:     ctx,
		cancel:  cancel,

		outs: make(chan []byte, 32),
		ins:  make(chan []byte, 32),

		peerMap:    &sync.Map{},
		peermap:    make(map[string]*peerEntry),
		peerLocker: &sync.RWMutex{},
	}
	go n.sendPeer(n.self)
	go n.receivePeer(n.self)

	return nil
}

func (n *Node) InitConsensus(consensusService libconsensus.ConsensusService) error {
	n.consensusService = consensusService
	return nil
}

func (n *Node) GetConfig() libcore.Config {
	return n.config
}

func (n *Node) getContractData(rootAccount libcore.Address, txm map[string]interface{}) (int64, interface{}, error) {
	entry, err := n.GetEntry(rootAccount)
	if err != nil {
		return 0, nil, err
	}
	ss := entry.storage

	from := util.ToString(&txm, "from")
	to := util.ToString(&txm, "to")

	_, fromAccount, err := as.NewAccountFromAddress(from)
	if err != nil {
		return 0, nil, err
	}

	_, toAccount, err := as.NewAccountFromAddress(to)
	if err != nil {
		return 0, nil, err
	}

	format := util.ToString(&txm, "format")
	usedCost, r, err := ss.GetContractData(fromAccount, toAccount, format)
	if err != nil {
		return 0, nil, err
	}
	return usedCost, r, nil
}

func (n *Node) callContract(rootAccount libcore.Address, txm map[string]interface{}) (int64, interface{}, error) {
	entry, err := n.GetEntry(rootAccount)
	if err != nil {
		return 0, nil, err
	}
	ss := entry.storage

	from := util.ToString(&txm, "from")
	to := util.ToString(&txm, "to")

	_, fromAccount, err := as.NewAccountFromAddress(from)
	if err != nil {
		return 0, nil, err
	}

	_, toAccount, err := as.NewAccountFromAddress(to)
	if err != nil {
		return 0, nil, err
	}

	method := util.ToString(&txm, "method")
	params, err := n.getParams(txm)
	if err != nil {
		return 0, nil, err
	}

	usedCost, r, err := ss.CallContract(fromAccount, toAccount, method, params)
	if err != nil {
		return 0, nil, err
	}
	return usedCost, r, nil
}

func (n *Node) signTransaction(rootAccount libcore.Address, txm map[string]interface{}) (string, *block.Transaction, error) {
	accountString := util.ToString(&txm, "account")
	_, account, err := as.NewAccountFromAddress(accountString)
	if err != nil {
		return "", nil, err
	}
	secret := util.ToString(&txm, "secret")
	gas := util.ToUint64(&txm, "gas")

	_, fromKey, err := as.NewKeyFromSecret(secret)
	if err != nil {
		return "", nil, err
	}
	fromAccount, err := fromKey.GetAddress()
	if err != nil {
		return "", nil, err
	}
	fromAddress := fromAccount.String()
	if fromAddress != account.String() {
		return "", nil, util.ErrorOfUnmatched("account", "in secret", fromAddress, account.String())
	}

	seq := n.getNextSequence(rootAccount, account)

	tx := &block.Transaction{
		TransactionType: block.TRANSACTION,

		Account:  account,
		Sequence: seq,
		Gas:      gas,
	}

	payloadInfo := &block.PayloadInfo{}
	if util.Has(&txm, "payload") {
		pxm := util.ToMap(&txm, "payload")
		if util.Has(&pxm, "contract") {
			contractInfo := &pb.ContractInfo{}

			cm := util.ToMap(&pxm, "contract")
			if util.Has(&cm, "inputs") {
				if inputString := util.ToString(&cm, "inputs"); len(inputString) > 0 {
					inputs := strings.Split(inputString, ",")
					list := make([][]byte, 0)
					for _, accountString := range inputs {
						_, account, err := as.NewAccountFromAddress(accountString)
						if err != nil {
							return "", nil, err
						}
						accountData, err := account.MarshalBinary()
						if err != nil {
							return "", nil, err
						}
						list = append(list, accountData)
					}
					contractInfo.Inputs = list
				}
				if inputs := util.ToArray(&cm, "inputs"); inputs != nil {
					list := make([][]byte, 0)
					for _, input := range inputs {
						accountString, ok := input.(string)
						if !ok {
							return "", nil, util.ErrorOfInvalid("input", "account")
						}
						_, account, err := as.NewAccountFromAddress(accountString)
						if err != nil {
							return "", nil, err
						}
						accountData, err := account.MarshalBinary()
						if err != nil {
							return "", nil, err
						}
						list = append(list, accountData)
					}
					contractInfo.Inputs = list
				}
			}
			if util.Has(&cm, "outputs") {
				if outputString := util.ToString(&cm, "outputs"); len(outputString) > 0 {
					outputs := strings.Split(outputString, ",")
					list := make([][]byte, 0)
					for _, accountString := range outputs {
						_, account, err := as.NewAccountFromAddress(accountString)
						if err != nil {
							return "", nil, err
						}
						accountData, err := account.MarshalBinary()
						if err != nil {
							return "", nil, err
						}
						list = append(list, accountData)
					}
					contractInfo.Outputs = list
				}
				if outputs := util.ToArray(&cm, "outputs"); outputs != nil {
					list := make([][]byte, 0)
					for _, output := range outputs {
						accountString, ok := output.(string)
						if !ok {
							return "", nil, util.ErrorOfInvalid("output", "account")
						}
						_, account, err := as.NewAccountFromAddress(accountString)
						if err != nil {
							return "", nil, err
						}
						accountData, err := account.MarshalBinary()
						if err != nil {
							return "", nil, err
						}
						list = append(list, accountData)
					}
					contractInfo.Outputs = list
				}
			}
			if util.Has(&cm, "method") {
				contractInfo.Method = util.ToString(&cm, "method")
			}
			if util.Has(&cm, "params") {
				params, err := n.getParams(cm)
				if err != nil {
					return "", nil, err
				}
				contractInfo.Params = params
			}
			contractData, err := core.Marshal(contractInfo)
			if err != nil {
				return "", nil, err
			}
			dataHash, err := cs.Hash(contractData)
			if err != nil {
				return "", nil, err
			}
			payloadInfo.Infos = append(payloadInfo.Infos, &block.DataInfo{
				Hash:    dataHash,
				Content: contractData,
			})
		}
		if util.Has(&pxm, "code") {
			codeInfo := &pb.CodeInfo{}

			cm := util.ToMap(&pxm, "code")
			if util.Has(&cm, "data") {
				codeString := util.ToString(&cm, "data")
				codeData, err := hex.DecodeString(codeString)
				if err != nil {
					return "", nil, err
				}
				codeInfo.Code = codeData
			} else if util.Has(&cm, "file") {
				filePath := util.ToString(&cm, "file")
				f, err := os.Open(filePath)
				if err != nil {
					return "", nil, err
				}
				defer f.Close()
				fileData, err := io.ReadAll(f)
				if err != nil {
					return "", nil, err
				}
				codeInfo.Code = fileData
			}
			if util.Has(&cm, "abi") {
				abiString := util.ToString(&cm, "abi")
				abiData, err := hex.DecodeString(abiString)
				if err != nil {
					return "", nil, err
				}
				codeInfo.Abi = abiData
			} else if util.Has(&cm, "json") {
				jsonPath := util.ToString(&cm, "json")
				f, err := os.Open(jsonPath)
				if err != nil {
					return "", nil, err
				}
				defer f.Close()
				jsonData, err := io.ReadAll(f)
				if err != nil {
					return "", nil, err
				}
				codeInfo.Abi = jsonData
			}

			codeData, err := core.Marshal(codeInfo)
			if err != nil {
				return "", nil, err
			}
			dataHash, err := cs.Hash(codeData)
			if err != nil {
				return "", nil, err
			}
			payloadInfo.Infos = append(payloadInfo.Infos, &block.DataInfo{
				Hash:    dataHash,
				Content: codeData,
			})
		}
		if util.Has(&pxm, "page") {
			pageInfo := &pb.PageInfo{}

			pm := util.ToMap(&pxm, "page")
			if util.Has(&pm, "name") {
				name := util.ToString(&pm, "name")
				pageInfo.Name = name
			}
			if util.Has(&pm, "data") {
				pageString := util.ToString(&pm, "data")
				pageData, err := hex.DecodeString(pageString)
				if err != nil {
					return "", nil, err
				}
				pageInfo.Data = pageData
			} else if util.Has(&pm, "file") {
				filePath := util.ToString(&pm, "file")
				f, err := os.Open(filePath)
				if err != nil {
					return "", nil, err
				}
				defer f.Close()
				fileData, err := io.ReadAll(f)
				if err != nil {
					return "", nil, err
				}
				pageInfo.Data = fileData
			}

			pageData, err := core.Marshal(pageInfo)
			if err != nil {
				return "", nil, err
			}
			dataHash, err := cs.Hash(pageData)
			if err != nil {
				return "", nil, err
			}
			payloadInfo.Infos = append(payloadInfo.Infos, &block.DataInfo{
				Hash:    dataHash,
				Content: pageData,
			})
		}
		if util.Has(&pxm, "meta") {
			metaInfo := &pb.MetaInfo{}

			pm := util.ToMap(&pxm, "meta")
			metaInfo.Symbol = util.ToString(&pm, "symbol")
			metaInfo.Total = util.ToInt64(&pm, "total")
			metaInfo.Items, err = n.getMetaItems(pm)
			if err != nil {
				return "", nil, err
			}
			metaData, err := core.Marshal(metaInfo)
			if err != nil {
				return "", nil, err
			}
			dataHash, err := cs.Hash(metaData)
			if err != nil {
				return "", nil, err
			}
			payloadInfo.Infos = append(payloadInfo.Infos, &block.DataInfo{
				Hash:    dataHash,
				Content: metaData,
			})
		}
		if util.Has(&pxm, "token") {
			tokenInfo := &pb.TokenInfo{}

			pm := util.ToMap(&pxm, "token")
			tokenInfo.Symbol = util.ToString(&pm, "symbol")
			tokenInfo.Index = util.ToUint64(&pm, "index")
			tokenInfo.Items, err = n.getTokenItems(pm)
			if err != nil {
				return "", nil, err
			}
			tokenData, err := core.Marshal(tokenInfo)
			if err != nil {
				return "", nil, err
			}
			dataHash, err := cs.Hash(tokenData)
			if err != nil {
				return "", nil, err
			}
			payloadInfo.Infos = append(payloadInfo.Infos, &block.DataInfo{
				Hash:    dataHash,
				Content: tokenData,
			})
		}
	}
	if len(payloadInfo.Infos) > 0 {
		tx.Payload = payloadInfo
	}
	err = cs.Sign(fromKey, tx)
	if err != nil {
		return "", nil, err
	}
	data, err := tx.MarshalBinary()
	if err != nil {
		return "", nil, err
	}
	err = n.verifyTransaction(rootAccount, tx)
	if err != nil {
		return "", nil, err
	}
	blob := libcore.Bytes(data).String()
	return blob, tx, nil
}

func (n *Node) getOptions(os string) []string {
	if len(os) == 0 {
		return nil
	}
	return strings.Split(os, ";")
}

func (n *Node) getMetaItems(cm map[string]interface{}) ([]*pb.MetaItem, error) {
	if itemString := util.ToString(&cm, "items"); len(itemString) > 0 {
		list := make([]*pb.MetaItem, 0)
		ps := strings.Split(itemString, ",")
		for i := 0; i < len(ps); i++ {
			items := strings.Split(ps[i], ":")
			if len(items) == 4 {
				name := items[0]
				t := items[1]
				options := n.getOptions(items[2])
				desc := items[3]

				_, err := core.GetDataTypeByName(t)
				if err != nil {
					return nil, err
				}

				list = append(list, &pb.MetaItem{
					Name:    name,
					Type:    t,
					Options: options,
					Desc:    desc,
				})
			} else {
				return nil, util.ErrorOfInvalid("meta items", itemString)
			}
		}
		return list, nil
	}
	if items := util.ToArray(&cm, "items"); items != nil {
		list := make([]*pb.MetaItem, 0)
		for i := 0; i < len(items); i++ {
			item := items[i]
			m, ok := item.(map[string]interface{})
			if !ok {
				return nil, util.ErrorOfInvalid("meta item", "not a map")
			}
			name := util.ToString(&m, "name")
			t := util.ToString(&m, "type")

			_, err := core.GetDataTypeByName(t)
			if err != nil {
				return nil, err
			}

			o := util.ToString(&m, "options")
			options := n.getOptions(o)

			desc := util.ToString(&m, "desc")

			list = append(list, &pb.MetaItem{
				Name:    name,
				Type:    t,
				Options: options,
				Desc:    desc,
			})
		}
		return list, nil
	}
	return nil, util.ErrorOfNotFound("meta items", "map")
}

func (n *Node) getTokenItems(cm map[string]interface{}) ([]*pb.TokenItem, error) {
	if itemString := util.ToString(&cm, "items"); len(itemString) > 0 {
		list := make([]*pb.TokenItem, 0)
		ps := strings.Split(itemString, ",")
		for i := 0; i < len(ps); i++ {
			items := strings.Split(ps[i], ":")
			if len(items) == 2 {
				name := items[0]
				value := items[1]

				list = append(list, &pb.TokenItem{
					Name:  name,
					Value: value,
				})
			} else {
				return nil, util.ErrorOfInvalid("token items", itemString)
			}
		}
		return list, nil
	}
	if items := util.ToArray(&cm, "items"); items != nil {
		list := make([]*pb.TokenItem, 0)
		for i := 0; i < len(items); i++ {
			item := items[i]
			m, ok := item.(map[string]interface{})
			if !ok {
				return nil, util.ErrorOfInvalid("token item", "not a map")
			}
			name := util.ToString(&m, "name")
			value := util.ToString(&m, "value")

			list = append(list, &pb.TokenItem{
				Name:  name,
				Value: value,
			})
		}
		return list, nil
	}
	return nil, util.ErrorOfNotFound("token items", "map")
}

func (n *Node) getParams(cm map[string]interface{}) ([][]byte, error) {
	if params := util.ToString(&cm, "params"); len(params) > 0 {
		list := make([][]byte, 0)
		ps := strings.Split(params, ",")
		for i := 0; i < len(ps); i++ {
			items := strings.Split(ps[i], ":")
			if len(items) == 2 {
				t, err := core.GetDataTypeByName(items[1])
				if err != nil {
					return nil, err
				}
				data, err := t.FromString(items[0])
				if err != nil {
					return nil, err
				}
				list = append(list, data)
			} else {
				return nil, util.ErrorOfInvalid("parameter", params)
			}
		}
		return list, nil
	}
	if params := util.ToArray(&cm, "params"); params != nil {
		list := make([][]byte, 0)
		for i := 0; i < len(params); i++ {
			item := params[i]
			m, ok := item.(map[string]interface{})
			if !ok {
				return nil, util.ErrorOfInvalid("parameter item", "not a map")
			}
			typeString := util.ToString(&m, "type")
			valueString := util.ToString(&m, "value")
			t, err := core.GetDataTypeByName(typeString)
			if err != nil {
				return nil, err
			}
			data, err := t.FromString(valueString)
			if err != nil {
				return nil, err
			}
			list = append(list, data)
		}
		return list, nil
	}
	return nil, util.ErrorOfNotFound("params", "in contract")
}

func (n *Node) verifyTransaction(rootAccount libcore.Address, tx libblock.Transaction) error {
	_, _, err := cs.Raw(tx, libcrypto.RawBinary)
	if err != nil {
		return err
	}
	_, err = n.consensusService.VerifyTransaction(rootAccount, tx)
	if err != nil {
		return err
	}
	return nil
}

func (n *Node) sendTransaction(rootAccount libcore.Address, tx libblock.Transaction) (libblock.TransactionWithData, error) {
	err := n.verifyTransaction(rootAccount, tx)
	if err != nil {
		return nil, err
	}
	hash := tx.GetHash()
	glog.Infoln("verify transaction", hash.String())

	txWithData, _, err := n.processTransaction(rootAccount, tx)
	if err != nil {
		return nil, err
	}
	return txWithData, nil
}

func (n *Node) processTransaction(rootAccount libcore.Address, tx libblock.Transaction) (libblock.TransactionWithData, libblock.Transaction, error) {
	n.transactionLocker.Lock()
	defer n.transactionLocker.Unlock()

	entry, err := n.GetEntry(rootAccount)
	if err != nil {
		return nil, nil, err
	}
	ss := entry.storage

	h, _, err := cs.Raw(tx, libcrypto.RawBinary)
	if err != nil {
		return nil, nil, err
	}
	ok, err := n.consensusService.VerifyTransaction(rootAccount, tx)
	if err != nil {
		return nil, nil, err
	}
	if !ok {
		return nil, nil, util.ErrorOfInvalid("verify", "transaction")
	}

	err = ss.CreateSandbox()
	if err != nil {
		return nil, nil, err
	}
	defer ss.CancelSandbox()
	result, states, err := n.consensusService.ProcessTransaction(rootAccount, tx)
	if err != nil {
		return nil, nil, err
	}
	datas, err := ss.CaptureSandbox()
	if err != nil {
		return nil, nil, err
	}
	r := &block.Receipt{
		TransactionResult: result,
		States:            states,
		Datas:             datas,
	}
	txWithData := &block.TransactionWithData{
		Transaction: tx,
		Receipt:     r,
		Date:        int64(time.Now().UnixNano() / 1e9),
	}

	// util.PrintJSON("txWithData", txWithData)
	ok, err = n.addTransaction(rootAccount, txWithData)
	if err != nil {
		return nil, nil, err
	}
	if ok {
		glog.Infoln(">>> receive transaction", h.String())
	} else {
		glog.Infoln(">>> drop exists transaction", h.String())
	}

	return txWithData, tx, nil
}

func (n *Node) getNextSequence(rootAccount libcore.Address, address libcore.Address) uint64 {
	entry, err := n.GetEntry(rootAccount)
	if err != nil {
		return uint64(1)
	}
	accountEntry, err := entry.GetAccountInfo(address)
	if err != nil {
		return uint64(1)
	}
	return accountEntry.Sequence + 1
}

func (n *Node) getRootAccount(item map[string]interface{}) (libcore.Address, error) {
	if item != nil && util.Has(&item, "root") {
		root := util.ToString(&item, "root")
		_, r, err := as.NewAccountFromAddress(root)
		if err != nil {
			return nil, err
		}
		return r, nil
	}
	return nil, nil
}

func loadFile(sfs *zipfs.FileSystem, name string) ([]byte, error) {
	f, err := sfs.Open(name)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	data, err := io.ReadAll(f)
	if err != nil {
		return nil, err
	}
	return data, nil
}

func (n *Node) VerifyInput(entry *Entry, input string) error {
	inputData, err := hex.DecodeString(input)
	if err != nil {
		return err
	}
	inputItem := &service.Item{}
	err = inputItem.UnmarshalBinary(inputData)
	if err != nil {
		return err
	}
	ok, err := cs.Verify(inputItem)
	if err != nil {
		return err
	}
	if !ok {
		return util.ErrorOfInvalid("verify", "message")
	}
	_, pk, err := as.NewPublicFromBytes(inputItem.GetPublicKey())
	if err != nil {
		return err
	}
	a, err := pk.GenerateAddress()
	if err != nil {
		return err
	}
	info, err := entry.GetAccountInfo(a)
	if err != nil {
		return err
	}
	if info == nil {
		return util.ErrorOfNotFound(a.String(), "account")
	}
	return nil
}

func (n *Node) startService(rootAccount libcore.Address, txm map[string]interface{}) (int64, interface{}, error) {
	entry, err := n.GetEntry(rootAccount)
	if err != nil {
		return 0, nil, err
	}
	if !util.Has(&txm, "input") {
		return 0, nil, util.ErrorOfEmpty("input", "service")
	}
	input := util.ToString(&txm, "input")
	err = n.VerifyInput(entry, input)
	if err != nil {
		return 0, nil, err
	}

	nameOrAddress := util.ToString(&txm, "service")
	serviceName := fmt.Sprintf("%s@%s", nameOrAddress, util.GetString(rootAccount))
	sfs, err := n.LoadServiceByNameOrAddress(serviceName)
	if err != nil {
		return 0, nil, err
	}
	defer sfs.Close()

	wasmCode, err := loadFile(sfs, "service.wasm")
	if err != nil {
		return 0, nil, err
	}
	wm, err := service.VerifyCode(nil, wasmCode)
	if err != nil {
		return 0, nil, err
	}
	at, err := service.CreateApplet()
	if err != nil {
		return 0, nil, err
	}
	serviceHash := at.GetHash()

	service := CreateService(nameOrAddress, wm, at)
	usedCost, ok, err := service.Start(1000000, input)
	if err != nil {
		return usedCost, nil, err
	}
	if !ok {
		return 0, nil, util.ErrorOfNotFound("start", "service")
	}
	entry.serviceMap.Store(serviceHash.String(), service)
	glog.Infoln(">>> start service", fmt.Sprintf("%s@%s", nameOrAddress, util.GetString(rootAccount)), serviceHash.String())
	return usedCost, serviceHash.String(), nil
}

func (n *Node) listService(rootAccount libcore.Address, txm map[string]interface{}) (int64, interface{}, error) {
	entry, err := n.GetEntry(rootAccount)
	if err != nil {
		return 0, nil, err
	}

	if !util.Has(&txm, "service") {
		return 0, nil, util.ErrorOfNotFound("parameter", "service")
	}

	ss := make(Services, 0)
	serviceName := util.ToString(&txm, "service")
	entry.serviceMap.Range(func(key any, value any) bool {
		service := value.(*Service)
		if service.nameOrAddress == serviceName {
			ss = append(ss, service)
		}
		return true
	})
	sort.Sort(ss)

	return 0, ss.List(), nil
}

func (n *Node) callService(rootAccount libcore.Address, txm map[string]interface{}) (int64, interface{}, error) {
	entry, err := n.GetEntry(rootAccount)
	if err != nil {
		return 0, nil, err
	}

	if !util.Has(&txm, "service") {
		return 0, nil, util.ErrorOfNotFound("parameter", "service")
	}
	service := util.ToString(&txm, "service")
	o, ok := entry.serviceMap.Load(service)
	if !ok {
		return 0, nil, util.ErrorOfNotFound(service, "service")
	}
	s := o.(*Service)

	if !util.Has(&txm, "input") {
		return 0, nil, util.ErrorOfNotFound(service, "input")
	}
	input := util.ToString(&txm, "input")
	usedCost, output, err := s.Process(1000000, input)
	if err != nil {
		return usedCost, nil, err
	}
	return usedCost, output, nil
}

func (n *Node) joinService(rootAccount libcore.Address, txm map[string]interface{}) (int64, interface{}, error) {
	entry, err := n.GetEntry(rootAccount)
	if err != nil {
		return 0, nil, err
	}

	if !util.Has(&txm, "service") {
		return 0, nil, util.ErrorOfNotFound("parameter", "service")
	}
	service := util.ToString(&txm, "service")
	o, ok := entry.serviceMap.Load(service)
	if !ok {
		return 0, nil, util.ErrorOfNotFound(service, "service")
	}
	s := o.(*Service)

	if !util.Has(&txm, "input") {
		return 0, nil, util.ErrorOfNotFound(service, "input")
	}
	input := util.ToString(&txm, "input")
	usedCost, output, err := s.Join(1000000, input)
	if err != nil {
		return usedCost, nil, err
	}
	return usedCost, output, nil
}

func (n *Node) leaveService(rootAccount libcore.Address, txm map[string]interface{}) (int64, interface{}, error) {
	entry, err := n.GetEntry(rootAccount)
	if err != nil {
		return 0, nil, err
	}

	if !util.Has(&txm, "service") {
		return 0, nil, util.ErrorOfNotFound("parameter", "service")
	}
	service := util.ToString(&txm, "service")
	o, ok := entry.serviceMap.Load(service)
	if !ok {
		return 0, nil, util.ErrorOfNotFound(service, "service")
	}
	s := o.(*Service)

	if !util.Has(&txm, "input") {
		return 0, nil, util.ErrorOfNotFound(service, "input")
	}
	input := util.ToString(&txm, "input")
	usedCost, output, err := s.Leave(1000000, input)
	if err != nil {
		return usedCost, nil, err
	}
	return usedCost, output, nil
}

func (n *Node) _call(params []interface{}, f func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error)) (interface{}, error) {
	l := len(params)
	if l > 0 {
		list := make([]interface{}, l)
		for i := 0; i < l; i++ {
			item, ok := params[i].(map[string]interface{})
			if !ok {
				return nil, util.ErrorOfInvalid("map", "parameter")
			}
			rootAccount, err := n.getRootAccount(item)
			if err != nil {
				return nil, err
			}
			result, err := f(rootAccount, item)
			if err != nil {
				return nil, err
			}
			list[i] = result
		}
		if l == 1 { // for one, just return the result instead of the array
			return list[0], nil
		}
		return list, nil
	}
	result, err := f(nil, nil)
	if err != nil {
		return nil, err
	}
	return result, nil
}

func (n *Node) Call(method string, params []interface{}) (interface{}, error) {
	switch method {
	case "blockNumber":
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			entry, err := n.GetEntry(rootAccount)
			if err != nil {
				return nil, err
			}
			return entry.GetBlockNumber(), nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "createWallet":
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			t := util.ToString(&item, "type")
			p := util.ToString(&item, "password")
			tt, k, err := as.GenerateFamilySeed(t + "." + p)
			if err != nil {
				return nil, err
			}
			a, err := k.GetAddress()
			if err != nil {
				return nil, err
			}
			address := a.String()
			pub, err := k.GetPublic()
			if err != nil {
				return nil, err
			}
			publicString, err := pub.MarshalText()
			if err != nil {
				return nil, err
			}
			priv, err := k.GetPrivate()
			if err != nil {
				return nil, err
			}
			privateString, err := priv.MarshalText()
			if err != nil {
				return nil, err
			}
			return &map[string]interface{}{
				"type":    tt.String(),
				"address": address,
				"private": string(privateString),
				"public":  string(publicString),
			}, nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "getBalance":
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			entry, err := n.GetEntry(rootAccount)
			if err != nil {
				return nil, err
			}
			ss := entry.storage

			address := util.ToString(&item, "address")
			_, a, err := as.NewAccountFromAddress(address)
			if err != nil {
				return nil, err
			}
			gas, err := ss.GetGas(a)
			if err != nil {
				return nil, err
			}
			return gas.String(), nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "getMeta":
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			entry, err := n.GetEntry(rootAccount)
			if err != nil {
				return nil, err
			}
			ss := entry.storage

			symbol := util.ToString(&item, "symbol")
			index, account, info, err := ss.ReadMeta(libcore.Symbol(symbol))
			if err != nil {
				return nil, err
			}
			return map[string]interface{}{
				"account": account.String(),
				"info":    info,
				"index":   index,
			}, nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "getToken":
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			entry, err := n.GetEntry(rootAccount)
			if err != nil {
				return nil, err
			}
			ss := entry.storage

			symbol := util.ToString(&item, "symbol")
			index := util.ToUint64(&item, "index")
			account, info, err := ss.ReadToken(libcore.Symbol(symbol), index)
			if err != nil {
				return nil, err
			}
			return map[string]interface{}{
				"account": account.String(),
				"info":    info,
			}, nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "getTransactionCount":
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			address := util.ToString(&item, "address")
			_, a, err := as.NewAccountFromAddress(address)
			if err != nil {
				return nil, err
			}
			seq := n.getNextSequence(rootAccount, a)
			return seq, nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "getTransactionReceipt":
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			entry, err := n.GetEntry(rootAccount)
			if err != nil {
				return nil, err
			}
			ms := entry.merkle

			hashString := util.ToString(&item, "hash")
			h, err := hex.DecodeString(hashString)
			if err != nil {
				return nil, err
			}
			txWithData, err := ms.GetTransactionByHash(libcore.Hash(h))
			if err != nil {
				return nil, err
			}
			receipt := txWithData.GetReceipt()
			_, err = block.HashReceipt(receipt)
			if err != nil {
				return nil, err
			}
			return receipt, nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "getTransactionByHash":
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			entry, err := n.GetEntry(rootAccount)
			if err != nil {
				return nil, err
			}
			ms := entry.merkle

			hashString := util.ToString(&item, "hash")
			h, err := hex.DecodeString(hashString)
			if err != nil {
				return nil, err
			}
			txWithData, err := ms.GetTransactionByHash(libcore.Hash(h))
			if err != nil {
				return nil, err
			}
			_, err = block.HashTransaction(txWithData)
			if err != nil {
				return nil, err
			}
			format := util.ToString(&item, "format")
			switch format {
			case "hex":
				data, err := txWithData.MarshalBinary()
				if err != nil {
					return nil, err
				}
				return hex.EncodeToString(data), nil
			}
			return txWithData, nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "getTransactionByIndex":
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			entry, err := n.GetEntry(rootAccount)
			if err != nil {
				return nil, err
			}
			ms := entry.merkle

			address := util.ToString(&item, "address")
			_, a, err := as.NewAccountFromAddress(address)
			if err != nil {
				return nil, err
			}
			index := util.ToUint64(&item, "index")

			txWithData, err := ms.GetTransactionByIndex(a, index)
			if err != nil {
				return nil, err
			}
			_, err = block.HashTransaction(txWithData)
			if err != nil {
				return nil, err
			}
			return txWithData, nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "getBlockByHash":
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			entry, err := n.GetEntry(rootAccount)
			if err != nil {
				return nil, err
			}
			ms := entry.merkle

			hashString := util.ToString(&item, "hash")
			h, err := hex.DecodeString(hashString)
			if err != nil {
				return nil, err
			}
			b, err := ms.GetBlockByHash(libcore.Hash(h))
			if err != nil {
				return nil, err
			}
			_, err = block.HashBlock(b)
			if err != nil {
				return nil, err
			}
			return b, nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "getBlockByNumber":
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			entry, err := n.GetEntry(rootAccount)
			if err != nil {
				return nil, err
			}
			ms := entry.merkle

			index := util.ToUint64(&item, "num")
			b, err := ms.GetBlockByIndex(index)
			if err != nil {
				return nil, err
			}
			_, err = block.HashBlock(b)
			if err != nil {
				return nil, err
			}
			return b, nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "getNodeInfo":
		address := n.self.GetAddress(n)
		publicData, err := n.self.Key.MarshalText()
		if err != nil {
			return nil, err
		}
		return &map[string]interface{}{
			"address": address,
			"public":  string(publicData),
			"node":    n.config.GetNodeId(),
		}, nil

	case "getData":
		maxCost := int64(1000000)
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			entry, err := n.GetEntry(rootAccount)
			if err != nil {
				return nil, err
			}
			ss := entry.storage

			hashString := util.ToString(&item, "hash")
			h, err := hex.DecodeString(hashString)
			if err != nil {
				return nil, err
			}
			format := util.ToString(&item, "format")
			usedCost, r, err := ss.GetData(libcore.Hash(h), format)
			if err != nil {
				return nil, err
			}

			maxCost -= usedCost
			if maxCost < 0 {
				return nil, util.ErrorOf("too long", "call", "contract")
			}

			return r, nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "getUserData":
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			entry, err := n.GetEntry(rootAccount)
			if err != nil {
				return nil, err
			}
			ss := entry.storage

			addressString := util.ToString(&item, "address")
			_, a, err := as.NewAccountFromAddress(addressString)
			if err != nil {
				return nil, err
			}
			accountString := util.ToString(&item, "account")
			_, b, err := as.NewAccountFromAddress(accountString)
			if err != nil {
				return nil, err
			}
			info, err := ss.ReadUser(a, b)
			if err != nil {
				return nil, err
			}
			return &map[string]interface{}{
				"account": b.String(),
				"key":     hex.EncodeToString(info.Key),
				"nonce":   hex.EncodeToString(info.Nonce),
				"hash":    libcore.Hash(info.Data.Hash).String(),
			}, nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "getContractData":
		maxCost := int64(1000000)
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			usedCost, r, err := n.getContractData(rootAccount, item)
			if err != nil {
				return nil, err
			}

			maxCost -= usedCost
			if maxCost < 0 {
				return nil, util.ErrorOf("too long", "call", "contract")
			}

			return r, nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "callContract":
		maxCost := int64(1000000)
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			usedCost, r, err := n.callContract(rootAccount, item)
			if err != nil {
				return nil, err
			}

			maxCost -= usedCost
			if maxCost < 0 {
				return nil, util.ErrorOf("too long", "call", "contract")
			}

			return r, nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "signTransaction":
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			blob, tx, err := n.signTransaction(rootAccount, item)
			if err != nil {
				return nil, err
			}
			hash := tx.GetHash()
			glog.Infoln("sign transaction", hash.String(), len(blob))
			return blob, nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "sendTransaction":
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			_, tx, err := n.signTransaction(rootAccount, item)
			if err != nil {
				return nil, err
			}
			_, err = n.sendTransaction(rootAccount, tx)
			if err != nil {
				return nil, err
			}

			hash := tx.GetHash()
			return hash, nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "sendRawTransaction":
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			blob := util.ToString(&item, "blob")

			data, err := hex.DecodeString(blob)
			if err != nil {
				return nil, err
			}
			tx := &block.Transaction{}
			err = tx.UnmarshalBinary(data)
			if err != nil {
				return nil, err
			}
			_, err = n.sendTransaction(rootAccount, tx)
			if err != nil {
				if util.IsTest() || util.IsDebug() {
					blobDir := "./consensus/data"
					isExists, isDir := util.Exists(blobDir)
					if isExists && isDir {
						blobFile := path.Join(blobDir, "tx.blob")
						e := util.WriteFile(blobFile, []byte(blob))
						if e != nil {
							return nil, e
						}
						glog.Infoln("write blob to ", blobFile)

						rawFile := path.Join(blobDir, "tx.raw")
						e = util.WriteFile(rawFile, []byte(fmt.Sprintf("%v", data)))
						if e != nil {
							return nil, e
						}
						glog.Infoln("write raw to ", rawFile)

						jsonFile := path.Join(blobDir, "tx.json")
						jsonBytes, e := json.MarshalIndent(tx, "", " ")
						if e != nil {
							return nil, e
						}
						e = util.WriteFile(jsonFile, jsonBytes)
						if e != nil {
							return nil, e
						}
						glog.Infoln("write json to ", jsonFile)
					}
				}
				glog.Error(err)
				return nil, err
			}

			hash := tx.GetHash()
			return hash, nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "getStateByHash":
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			entry, err := n.GetEntry(rootAccount)
			if err != nil {
				return nil, err
			}
			ms := entry.merkle

			hashString := util.ToString(&item, "hash")
			h, err := hex.DecodeString(hashString)
			if err != nil {
				return nil, err
			}
			s, err := ms.GetStateByHash(libcore.Hash(h))
			if err != nil {
				return nil, err
			}
			_, err = block.HashState(s)
			if err != nil {
				return nil, err
			}
			return s, nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "getStateByAddress":
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			stateTypeName := util.ToString(&item, "type")
			address := util.ToString(&item, "address")
			stateType := libblock.GetStateTypeByName(stateTypeName)
			switch stateType {
			case block.ACCOUNT_STATE:
				_, a, err := as.NewAccountFromAddress(address)
				if err != nil {
					return nil, err
				}
				entry, err := n.GetEntry(rootAccount)
				if err != nil {
					return nil, err
				}
				s, err := entry.GetAccountInfo(a)
				if err != nil {
					return nil, err
				}
				_, err = block.HashState(s)
				if err != nil {
					return nil, err
				}
				return s, nil
			default:
				return nil, util.ErrorOfUnknown("state", fmt.Sprintf("%d(%s)", stateType, stateTypeName))
			}
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "startService":
		maxCost := int64(1000000)
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			usedCost, r, err := n.startService(rootAccount, item)
			if err != nil {
				return nil, err
			}

			maxCost -= usedCost
			if maxCost < 0 {
				return nil, util.ErrorOf("too long", "start", "service")
			}

			return r, nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "listService":
		maxCost := int64(1000000)
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			usedCost, r, err := n.listService(rootAccount, item)
			if err != nil {
				return nil, err
			}
			maxCost -= usedCost
			if maxCost < 0 {
				return nil, util.ErrorOf("too long", "list", "service")
			}
			return r, nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "callService":
		maxCost := int64(2000000)
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			usedCost, r, err := n.callService(rootAccount, item)
			if err != nil {
				return nil, err
			}

			maxCost -= usedCost
			if maxCost < 0 {
				return nil, util.ErrorOf("too long", "call", "service")
			}

			return r, nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "joinService":
		maxCost := int64(2000000)
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			usedCost, r, err := n.joinService(rootAccount, item)
			if err != nil {
				return nil, err
			}

			maxCost -= usedCost
			if maxCost < 0 {
				return nil, util.ErrorOf("too long", "join", "service")
			}

			return r, nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "leaveService":
		maxCost := int64(2000000)
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			usedCost, r, err := n.leaveService(rootAccount, item)
			if err != nil {
				return nil, err
			}

			maxCost -= usedCost
			if maxCost < 0 {
				return nil, util.ErrorOf("too long", "leave", "service")
			}

			return r, nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "messageNumber":
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			entry, err := n.GetEntry(rootAccount)
			if err != nil {
				return nil, err
			}
			if !util.Has(&item, "service") {
				return nil, util.ErrorOfNotFound("parameter", "service")
			}
			service := util.ToString(&item, "service")
			o, ok := entry.serviceMap.Load(service)
			if !ok {
				return nil, util.ErrorOfNotFound(service, "service")
			}
			s := o.(*Service)
			return s.at.GetNumber(), nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "getMessageByIndex":
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			entry, err := n.GetEntry(rootAccount)
			if err != nil {
				return nil, err
			}
			if !util.Has(&item, "service") {
				return nil, util.ErrorOfNotFound("parameter", "service")
			}
			service := util.ToString(&item, "service")
			o, ok := entry.serviceMap.Load(service)
			if !ok {
				return nil, util.ErrorOfNotFound(service, "service")
			}
			s := o.(*Service)

			if !util.Has(&item, "index") {
				return nil, util.ErrorOfNotFound("parameter", "index")
			}
			index := util.ToUint64(&item, "index")
			msg, err := s.at.GetMessageByIndex(index)
			if err != nil {
				return nil, err
			}
			format := util.ToString(&item, "format")
			mo, err := msg.Json(format)
			if err != nil {
				return nil, err
			}
			return mo, nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "getMessageByHash":
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			entry, err := n.GetEntry(rootAccount)
			if err != nil {
				return nil, err
			}
			if !util.Has(&item, "service") {
				return nil, util.ErrorOfNotFound("parameter", "service")
			}
			service := util.ToString(&item, "service")
			o, ok := entry.serviceMap.Load(service)
			if !ok {
				return nil, util.ErrorOfNotFound(service, "service")
			}
			s := o.(*Service)

			if !util.Has(&item, "hash") {
				return nil, util.ErrorOfNotFound("parameter", "hash")
			}
			hash := util.ToString(&item, "hash")
			msg, err := s.at.GetMessageByHash(hash)
			if err != nil {
				return nil, err
			}
			format := util.ToString(&item, "format")
			mo, err := msg.Json(format)
			if err != nil {
				return nil, err
			}
			return mo, nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	case "dump":
		result, err := n._call(params, func(rootAccount libcore.Address, item map[string]interface{}) (interface{}, error) {
			entry, err := n.GetEntry(rootAccount)
			if err != nil {
				return nil, err
			}
			ss := entry.storage

			if util.IsTest() || util.IsDebug() {
				ss.Dump(storage.LogPrinter{})
			}
			return ss.RootHash(), nil
		})
		if err != nil {
			return nil, err
		}
		return result, nil

	default:
		return nil, util.ErrorOfNotFound("method", method)
	}
}

func (n *Node) checkServices(entry *Entry) {
	for {
		nowTime := time.Now().Unix()
		serviceCount := 0
		removes := make([]string, 0)
		entry.serviceMap.Range(func(key any, value any) bool {
			name := key.(string)
			service := value.(*Service)
			if (nowTime - service.lastUsedTime) > (60 * 30) {
				removes = append(removes, name)
			}
			serviceCount++
			return true
		})
		removeCount := len(removes)
		for i := 0; i < removeCount; i++ {
			name := removes[i]
			v, ok := entry.serviceMap.Load(name)
			if ok {
				service := v.(*Service)
				service.Stop(1000000)
			}
			entry.serviceMap.Delete(name)
		}
		if serviceCount > 0 {
			glog.Infoln(fmt.Sprintf(">>> service@%s", util.GetString(entry.root)), serviceCount, removeCount)
		}
		time.Sleep(time.Minute)
	}
}

func (n *Node) requestBlocks(entry *Entry) {
	for {
		e, ok := <-entry.requestChan
		if !ok {
			return
		}
		peerEntry := n.getPeerEntry(e.p, entry.root)
		if e.p.running && peerEntry.running {
			select {
			case <-e.p.ctx.Done():
				return
			default:
				peerEntry.lastTime = e.t
				err := n.sendBlock(entry, e.p, uint64(e.r.BlockNumber))
				if err != nil {
					glog.Error(err)
				}
			}
		}
	}
}

func (n *Node) replyBlocks(entry *Entry) {
	for {
		b, ok := <-entry.replyChan
		if !ok {
			return
		}
		err := n.processBlock(entry, b)
		if err != nil {
			glog.Error(err)
		}
		err = n.processCache(entry)
		if err != nil {
			glog.Error(err)
		}
	}
}

func (n *Node) sendBlockReply(entry *Entry, b *block.Block) bool {
	p, ok := entry.replyMap.Load(b.GetHash().String())
	if ok {
		n.SendPeerInfo(entry.root, p.(*Peer))
	}
	entry.replyMap.Delete(b.GetHash().String())
	entry.replyMap.Delete(fmt.Sprintf("%d", b.GetIndex()))
	entry.requestMap.Delete(fmt.Sprintf("%d", b.GetIndex()))
	return ok
}

func (n *Node) processCache(entry *Entry) error {
	rootAccount := entry.root
	for {
		i := entry.GetBlockNumber() + 1
		lb, ok := entry.replyMap.Load(fmt.Sprintf("%d", i))
		if !ok {
			break
		}
		lastBlock := lb.(*block.Block)
		_, err := n.VerifyBlock(rootAccount, lastBlock)
		if err != nil {
			glog.Error(err)
		} else {
			glog.Infof("<<< verify cache block @%s: %d, %s, %d", util.GetString(rootAccount), lastBlock.GetIndex(), lastBlock.GetHash().String(), len(lastBlock.GetTransactions()))
			err = n.AddBlock(rootAccount, lastBlock)
			if err != nil {
				glog.Error(err)
			} else {
				glog.Infof("<<< add cache block @%s: %d, %s, %d", util.GetString(rootAccount), lastBlock.GetIndex(), lastBlock.GetHash().String(), len(lastBlock.GetTransactions()))
			}
		}
		n.sendBlockReply(entry, lastBlock)
		if err != nil {
			break
		}
	}
	entry.replyMap.Range(func(k, v interface{}) bool {
		lb, ok := v.(*block.Block)
		if ok && int64(lb.GetIndex()) <= entry.GetBlockNumber() {
			glog.Infof("<<< clear block @%s: %d, %d, %s, %d", util.GetString(rootAccount), entry.GetBlockNumber(), lb.GetIndex(), lb.GetHash().String(), len(lb.GetTransactions()))
			n.sendBlockReply(entry, lb)
		}
		return true
	})
	return nil
}

func (n *Node) processBlock(entry *Entry, b *block.Block) error {
	rootAccount := b.GetAccount()
	h := b.GetHash()
	if int64(b.GetIndex()) <= entry.GetBlockNumber() {
		ok := n.sendBlockReply(entry, b)
		if ok {
			glog.Infof("<<< drop block @%s: %d, %d, %s, %d", util.GetString(rootAccount), entry.GetBlockNumber(), b.GetIndex(), h.String(), len(b.GetTransactions()))
		}
		return nil
	}
	if int64(b.GetIndex()) != (entry.GetBlockNumber() + 1) {
		glog.Infof("<<< cache block @%s: %d, %d, %s, %d", util.GetString(rootAccount), entry.GetBlockNumber(), b.GetIndex(), h.String(), len(b.GetTransactions()))
		return nil
	}
	_, err := n.VerifyBlock(rootAccount, b)
	if err != nil {
		return err
	}
	glog.Infof("<<< verify block @%s: %d, %s, %d", util.GetString(rootAccount), b.GetIndex(), h.String(), len(b.GetTransactions()))
	err = n.AddBlock(rootAccount, b)
	if err != nil {
		return err
	}
	glog.Infof("<<< add block @%s: %d, %s, %d", util.GetString(rootAccount), b.GetIndex(), h.String(), len(b.GetTransactions()))
	n.sendBlockReply(entry, b)
	return nil
}

func (n *Node) getMerkleService(rootAccount libcore.Address) (libstore.MerkleService, error) {
	ms, err := merkle.NewMerkleService(n.config, cs, rootAccount)
	if err != nil {
		return nil, err
	}
	return ms, nil
}

func (n *Node) getStorageService(rootAccount libcore.Address) (*storage.StorageService, error) {
	ss, err := storage.NewCategoryService(n.config, rootAccount)
	if err != nil {
		return nil, err
	}
	// ss, err := storage.NewStorageService(n.config, rootAccount)
	// if err != nil {
	// 	return nil, err
	// }
	return ss, nil
}

func (n *Node) addTransaction(rootAccount libcore.Address, txWithData libblock.TransactionWithData) (bool, error) {
	_, err := block.HashTransaction(txWithData)
	if err != nil {
		return false, err
	}

	entry, err := n.GetEntry(rootAccount)
	if err != nil {
		return false, err
	}

	h := txWithData.GetTransaction().GetHash().String()
	_, ok := entry.txmap[h]
	if ok {
		return false, util.ErrorOf("already exists", "transaction", h)
	}

	entry.txlist = append(entry.txlist, txWithData)
	entry.txmap[h] = txWithData
	return true, nil
}

func (n *Node) _generateBlock(rootAccount libcore.Address, list []libblock.TransactionWithData, rb libblock.Block) (libblock.Block, error) {
	config := n.config
	entry, err := n.GetEntry(rootAccount)
	if err != nil {
		return nil, err
	}
	ms := entry.merkle
	ss := entry.storage

	v := entry.ValidatedBlock

	var b *block.Block
	if v == nil { //genesis
		if len(list) > 0 {
			return nil, util.ErrorOfInvalid("transactions", "genesis block")
		}
		var states []libblock.State
		if rootAccount != nil {
			gasAccount := config.GetGasAccount()
			states = []libblock.State{
				&block.AccountState{
					State: block.State{
						StateType:  block.ACCOUNT_STATE,
						Account:    rootAccount,
						Sequence:   uint64(0),
						BlockIndex: uint64(0),
					},
				},
			}
			if gasAccount.String() != rootAccount.String() {
				states = append(states, &block.AccountState{
					State: block.State{
						StateType:  block.ACCOUNT_STATE,
						Account:    gasAccount,
						Sequence:   uint64(0),
						BlockIndex: uint64(0),
					},
				})
			}
		} else {
			account := n.config.GetGasAccount()
			// info := &pb.MetaInfo{
			// 	Symbol: block.ACCOUNT_STATE.String(),
			// 	Total:  int64(-1),
			// 	Items: []*pb.MetaItem{
			// 		{
			// 			Name:    "account",
			// 			Type:    core.CORE_DATA_STRING.String(),
			// 			Options: make([]string, 0),
			// 			Desc:    "the account",
			// 		},
			// 	},
			// }
			// dataInfo, err := ss.WriteMeta(account, info)
			// if err != nil {
			// 	return nil, err
			// }
			states = []libblock.State{
				&block.AccountState{
					State: block.State{
						StateType:  block.ACCOUNT_STATE,
						Account:    account,
						Sequence:   uint64(0),
						BlockIndex: uint64(0),
					},
					// Token: dataInfo,
				},
			}
		}

		for i := 0; i < len(states); i++ {
			state := states[i]
			err := ms.PutState(state)
			if err != nil {
				return nil, err
			}
		}

		b = &block.Block{
			Account:    rootAccount,
			BlockIndex: uint64(0),
			ParentHash: func(rb libblock.Block) libcore.Hash {
				if rb != nil {
					return rb.GetHash()
				}
				return libcrypto.ZeroHash(cs)
			}(rb),
			Transactions:    []libblock.TransactionWithData{},
			TransactionHash: ms.GetTransactionRoot(),

			States:    states,
			StateHash: ms.GetStateRoot(),

			RootHash: ss.RootHash(),

			Timestamp: func(rb libblock.Block) int64 {
				if rb != nil {
					return rb.GetTime()
				}
				return time.Now().UnixNano()
			}(rb),
		}

		err := ms.Cancel()
		if err != nil {
			return nil, err
		}
	} else {
		glog.Infof("=== package %d transactions in block %d", len(list), v.GetIndex()+1)
		ss.CreateSandbox()
		defer ss.CancelSandbox()

		stateMap := map[string][]uint64{}
		for i := 0; i < len(list); i++ {
			txWithData := list[i]

			r := txWithData.GetReceipt()
			r.SetTransactionIndex(uint32(i))
			r.SetBlockIndex(v.GetIndex() + 1)
			states := r.GetStates()
			for j := 0; j < len(states); j++ {
				s := states[j]
				s.SetBlockIndex(v.GetIndex() + 1)

				keys := s.GetStateKey()
				for k := 0; k < len(keys); k++ {
					key := fmt.Sprintf("%d-%s", s.GetStateType(), keys[k])
					index := s.GetIndex()
					stateMap[key] = []uint64{uint64(i), index}
				}
			}

			err := ms.PutTransaction(txWithData)
			if err != nil {
				return nil, err
			}

			rp := r.(*block.Receipt)
			err = ss.RestoreSandbox(rp.Datas)
			if err != nil {
				return nil, err
			}

			glog.Infof("=== %d %s", i, txWithData.GetTransaction().GetHash().String())
		}

		states := make([]libblock.State, 0)
		hashMap := make(map[string]libblock.State)
		for i := 0; i < len(list); i++ {
			txWithData := list[i]

			r := txWithData.GetReceipt()
			rs := r.GetStates()
			for j := 0; j < len(rs); j++ {
				s := rs[j]

				keys := s.GetStateKey()
				for k := 0; k < len(keys); k++ {
					key := fmt.Sprintf("%d-%s", s.GetStateType(), keys[k])
					item, sok := stateMap[key]
					_, hok := hashMap[s.GetHash().String()]
					if sok && !hok && item[0] == uint64(i) && item[1] == s.GetIndex() {
						states = append(states, s)
						hashMap[s.GetHash().String()] = s
					}
				}
			}
		}

		for i := 0; i < len(states); i++ {
			state := states[i]
			err := ms.PutState(state)
			if err != nil {
				return nil, err
			}
		}

		err := ss.UpdateSandbox()
		if err != nil {
			return nil, err
		}

		b = &block.Block{
			Account:    rootAccount,
			BlockIndex: v.GetIndex() + 1,
			ParentHash: v.GetHash(),

			Transactions:    list,
			TransactionHash: ms.GetTransactionRoot(),

			States:    states,
			StateHash: ms.GetStateRoot(),

			RootHash: ss.RootHash(),

			Timestamp: time.Now().UnixNano(),
		}

		err = ms.Cancel()
		if err != nil {
			return nil, err
		}
	}

	_, _, err = cs.Raw(b, libcrypto.RawBinary)
	if err != nil {
		return nil, err
	}

	return b, nil
}

func (n *Node) AddBlock(rootAccount libcore.Address, b libblock.Block) error {
	n.transactionLocker.Lock()
	defer n.transactionLocker.Unlock()

	entry, err := n.GetEntry(rootAccount)
	if err != nil {
		return err
	}
	ms := entry.merkle
	ss := entry.storage

	err = ss.CommitSandbox()
	if err != nil {
		return err
	}
	err = ms.PutBlock(b)
	if err != nil {
		return err
	}
	err = ms.Commit()
	if err != nil {
		return err
	}
	entry.ValidatedBlock = b

	e := n.getPeerEntry(n.self, rootAccount)
	e.BlockNumber = int64(b.GetIndex())

	return nil
}

func (n *Node) VerifyParent(rootAccount libcore.Address, b libblock.Block) error {
	if rootAccount != nil {
		if b.GetParentHash().IsZero() {
			return util.ErrorOfInvalid("the parent hash of the genesis block", "block")
		}
		rootEntry, err := n.GetEntry(nil)
		if err != nil {
			return err
		}
		_, err = rootEntry.GetAccountInfo(rootAccount)
		if err != nil {
			return err
		}
		_, err = rootEntry.merkle.GetBlockByHash(b.GetParentHash())
		if err != nil {
			return err
		}
	} else {
		if !b.GetParentHash().IsZero() {
			return util.ErrorOfInvalid("the parent hash of the genesis block", "block")
		}
	}
	return nil
}

func (n *Node) VerifyBlock(rootAccount libcore.Address, b libblock.Block) (ok bool, err error) {
	n.transactionLocker.Lock()
	defer n.transactionLocker.Unlock()

	entry, err := n.GetEntry(rootAccount)
	if err != nil {
		return false, err
	}
	ms := entry.merkle
	ss := entry.storage

	if entry.ValidatedBlock != nil {
		if b.GetIndex() != (entry.ValidatedBlock.GetIndex() + 1) {
			return false, util.ErrorOfUnmatched("index", "block", (entry.ValidatedBlock.GetIndex() + 1), b.GetIndex())
		}
		if b.GetParentHash().String() != entry.ValidatedBlock.GetHash().String() {
			return false, util.ErrorOfUnmatched("parent hash", "block", entry.ValidatedBlock.GetHash().String(), b.GetParentHash().String())
		}
	} else {
		if b.GetIndex() != 0 {
			return false, util.ErrorOfInvalid("index", "block")
		}
		err = n.VerifyParent(rootAccount, b)
		if err != nil {
			return false, err
		}
	}

	ok = true
	err = nil

	defer func() {
		if !ok || err != nil {
			ss.CancelSandbox()
			ms.Cancel()
		}
	}()

	err = ss.CreateSandbox()
	if err != nil {
		ok = false
		return
	}

	transactions := b.GetTransactions()
	l := len(transactions)
	for i := 0; i < l; i++ {
		txWithData := transactions[i]
		tx := txWithData.GetTransaction()

		ok, err = n.consensusService.VerifyTransaction(rootAccount, tx)
		if err != nil {
			return
		}
		if !ok {
			err = util.ErrorOfInvalid("transaction", tx.GetHash().String())
			return
		}

		err = ss.CreateSandbox()
		if err != nil {
			ok = false
			return
		}
		newResult, newStates, e := n.consensusService.ProcessTransaction(rootAccount, tx)
		if e != nil {
			err = ss.CancelSandbox()
			if err != nil {
				glog.Error(err)
			}
			ok = false
			err = e
			return
		}
		datas, e := ss.CaptureSandbox()
		if e != nil {
			ok = false
			err = e
			return
		}
		newReceipt := &block.Receipt{
			TransactionResult: newResult,
			States:            newStates,
			Datas:             datas,
		}
		newWithData := &block.TransactionWithData{
			Transaction: tx,
			Receipt:     newReceipt,
			Date:        int64(time.Now().UnixNano() / 1e9),
		}
		err = ss.CommitSandbox()
		if err != nil {
			ok = false
			return
		}

		arh, _, e := cs.Raw(txWithData.GetReceipt(), libcrypto.RawBinary)
		if e != nil {
			ok = false
			err = e
			return
		}
		brh, _, e := cs.Raw(newWithData.GetReceipt(), libcrypto.RawBinary)
		if e != nil {
			ok = false
			err = e
			return
		}
		if arh.String() != brh.String() {
			ok = false
			err = util.ErrorOfUnmatched("raw hash", "transaction receipt", arh.String(), brh.String())
			return
		}

		err = ms.PutTransaction(txWithData)
		if err != nil {
			ok = false
			return
		}
	}

	states := b.GetStates()
	l = len(states)
	for i := 0; i < l; i++ {
		state := states[i]
		err = ms.PutState(state)
		if err != nil {
			ok = false
			return
		}
	}

	transactionHash := ms.GetTransactionRoot()
	stateHash := ms.GetStateRoot()
	if b.GetTransactionHash().String() != transactionHash.String() {
		ok = false
		err = util.ErrorOfUnmatched("hash", "transaction", b.GetTransactionHash().String(), transactionHash.String())
		return
	}
	if b.GetStateHash().String() != stateHash.String() {
		ok = false
		err = util.ErrorOfUnmatched("hash", "state", b.GetStateHash().String(), stateHash.String())
		return
	}

	blk := b.(*block.Block)
	srh := ss.RootHash()
	sbh := blk.GetRootHash()
	if srh.String() != sbh.String() {
		ok = false
		err = util.ErrorOfUnmatched("root hash", "block", srh.String(), sbh.String())
		return
	}

	return
}

func (n *Node) GenerateBlock(rootAccount libcore.Address, rb libblock.Block) (libblock.Block, error) {
	n.transactionLocker.Lock()
	defer n.transactionLocker.Unlock()

	entry, err := n.GetEntry(rootAccount)
	if err != nil {
		return nil, err
	}
	list := entry.txlist
	entry.txlist = make([]libblock.TransactionWithData, 0)
	entry.txmap = make(map[string]libblock.TransactionWithData)

	return n._generateBlock(rootAccount, list, rb)
}

func (n *Node) generate() {
	for {
		util.Sleep(
			200*time.Millisecond,
			time.Duration(time.Duration(n.config.GetBlockDuration())*time.Second),
			n._hasTransaction,
			n._listTransaction,
		)
	}
}

func (n *Node) _listTransaction(_ []interface{}) {
	for root, entry := range n.entrymap {
		if entry.Consensused {
			glog.Infof("=== @%s: block %d, %s, prepare %d, %d", root, entry.GetBlockNumber(), entry.GetBlockHash(), entry.GetBlockNumber()+1, len(entry.txlist))
		} else {
			if entry.Synchronized {
				glog.Infof("=== @%s: block %d, %s, broadcast %d, %d", root, entry.GetBlockNumber(), entry.GetBlockHash(), entry.GetBlockNumber()+1, len(entry.txlist))
			} else {
				glog.Infof("=== @%s: block %d, %s, cache %d, %d", root, entry.GetBlockNumber(), entry.GetBlockHash(), entry.GetBlockNumber()+1, len(entry.txlist))
			}
		}
	}
}

func (n *Node) _hasTransaction(_ []interface{}) bool {
	hasTx := false
	for _, entry := range n.entrymap {
		rootAccount := entry.root
		if (entry.Synchronized || entry.Consensused) && len(entry.txlist) > 0 {
			hasTx = hasTx || true

			b, err := n.GenerateBlock(rootAccount, nil)
			if err != nil {
				glog.Error(err)
			} else {
				h, err := block.HashBlock(b)
				if err != nil {
					glog.Error(err)
				} else {
					glog.Infof("=== @%s: generate block %d, %s, %d", util.GetString(rootAccount), b.GetIndex(), h.String(), len(b.GetTransactions()))
					data, err := b.MarshalBinary()
					if err != nil {
						glog.Error(err)
					} else {
						n.broadcast(data)
					}
				}
			}
		}
	}
	return hasTx
}

func (n *Node) newId() uint64 {
	return atomic.AddUint64(&n.messageId, 1)
}

func (n *Node) broadcast(data []byte) {
	n.self.ins <- data
	msgData, err := n.EncodeMessage(data)
	if err != nil {
		glog.Error(err)
	} else {
		list := n.ListPeers()
		for i := 0; i < len(list); i++ {
			p := list[i]

			if p.running {
				select {
				case <-p.ctx.Done():
					continue
				default:
					p.outs <- msgData
				}
			}
		}
	}
	glog.Infof(">>> broadcast message %s(%d)", core.GetInfo(data), len(msgData))
}

func (n *Node) connect() {
	config := n.config
	for {
		for root, entry := range n.entrymap {
			rootAccount := entry.root
			list := n.ListPeersBy(rootAccount)
			e := n.getPeerEntry(n.self, rootAccount)
			e.PeerCount = int64(len(list))

			if !entry.Consensused {
				glog.Infoln("###", "@"+root)
				glog.Infof("---: %d, %v, %v(%v), %d, %d", 0, n.self.Id, e.status, e.PeerStatus, e.BlockNumber, e.PeerCount)
				for i := 0; i < len(list); i++ {
					p := list[i]
					e := n.getPeerEntry(p, rootAccount)
					glog.Infof("---: %d, %v, %v(%v), %d, %d", i+1, p.Id, e.status, e.PeerStatus, e.BlockNumber, e.PeerCount)
				}
			}
			if len(config.GetBootstraps()) == 0 {
				entry.Synchronized = true
				entry.Consensused = true
			}
		}
		time.Sleep(time.Duration(config.GetBlockDuration()) * time.Second)
	}
}

func (n *Node) ConnectTo(rootAccount libcore.Address, p *Peer) {
	n.SendPeerInfo(rootAccount, p)
}

func (n *Node) PrepareSynchronized(rootAccount libcore.Address) bool {
	root := util.GetString(rootAccount)
	list := n.ListPeersBy(rootAccount)
	count := int64(0)
	entry, err := n.GetEntry(rootAccount)
	if err != nil {
		glog.Error(err)
		return false
	}
	syncCount := n.config.GetSynchronizedCount()
	currentBlock := entry.GetBlockNumber()
	currentCount := int64(len(list))
	for i := 0; i < len(list); i++ {
		p := list[i]
		e, ok := p.peermap[root]
		if ok {
			if e.status >= PeerKnown && e.BlockNumber == currentBlock && (e.PeerCount == currentCount || (n.config.GetMaxPeerCount() >= 0 && e.PeerCount >= int64(syncCount))) {
				count++
			} else {
				n.SendPeerInfo(e.root, p)
			}
		}
	}
	if count > 0 && (count == currentCount || (n.config.GetMaxPeerCount() >= 0 && count >= int64(syncCount))) {
		for i := 0; i < len(list); i++ {
			p := list[i]
			e, ok := p.peermap[root]
			if ok {
				e.status = PeerSynchronized
				e.PeerStatus = PeerSynchronized

				e.lastSendBlock = -1
				e.lastRequestBlock = -1
			}
		}
		return true
	}
	return false
}

func (n *Node) PrepareConsensused(rootAccount libcore.Address) bool {
	root := util.GetString(rootAccount)
	list := n.ListPeersBy(rootAccount)
	count := int64(0)
	currentCount := int64(len(list))
	for i := 0; i < len(list); i++ {
		p := list[i]
		e, ok := p.peermap[root]
		if ok {
			if e.status >= PeerSynchronized {
				count++
			} else {
				n.SendPeerInfo(e.root, p)
			}
		}
	}
	if count > 0 && (count == currentCount) {
		for i := 0; i < len(list); i++ {
			p := list[i]
			e, ok := p.peermap[root]
			if ok {
				e.status = PeerConsensused
				e.PeerStatus = PeerConsensused
			}
		}
		return true
	}
	return false
}

func (n *Node) load(rootAccount libcore.Address, entry *Entry) error {
	n.transactionLocker.Lock()
	defer n.transactionLocker.Unlock()

	e := n.getPeerEntry(n.self, rootAccount)
	current := uint64(0)
	for {
		b, err := entry.merkle.GetBlockByIndex(current)
		if err != nil {
			glog.Error(err)
			break
		}
		_, err = block.HashBlock(b)
		if err != nil {
			return err
		}
		if entry.ValidatedBlock != nil {
			if b.GetIndex() != (entry.ValidatedBlock.GetIndex() + 1) {
				return util.ErrorOfInvalid("block index", fmt.Sprintf("%d != %d", b.GetIndex(), (entry.ValidatedBlock.GetIndex()+1)))
			}
			if !b.GetParentHash().Equals(entry.ValidatedBlock.GetHash()) {
				return util.ErrorOfInvalid("block hash", fmt.Sprintf("%s != %s", b.GetParentHash().String(), entry.ValidatedBlock.GetHash().String()))
			}
		} else {
			if b.GetIndex() != 0 {
				return util.ErrorOfInvalid("genesis block", fmt.Sprintf("%d, %s", b.GetIndex(), b.GetHash().String()))
			}
			err := n.VerifyParent(rootAccount, b)
			if err != nil {
				return err
			}
		}
		entry.ValidatedBlock = b

		allData, err := b.Raw(libcrypto.RawBinary)
		if err != nil {
			glog.Error(err)
			break
		}
		ignoreData, err := b.Raw(libcrypto.RawIgnoreVariableFields)
		if err != nil {
			glog.Error(err)
			break
		}
		signData, err := b.Raw(libcrypto.RawIgnoreSigningFields)
		if err != nil {
			glog.Error(err)
			break
		}
		hashData, err := b.Raw(libcrypto.RawIgnoreContent)
		if err != nil {
			glog.Error(err)
			break
		}
		glog.Infoln("load block", current, b.GetHash().String(), len(allData), len(ignoreData), len(signData), len(hashData))

		current++
	}
	e.BlockNumber = entry.GetBlockNumber()
	e.status = PeerConsensused
	e.PeerStatus = PeerConsensused

	return nil
}

func (n *Node) Dump(rootAccount libcore.Address, printer core.Printer) {
	entry, err := n.GetEntry(rootAccount)
	if err != nil {
		printer.Printf(err.Error())
	} else {
		ss := entry.storage
		ss.Dump(printer)
	}
}

func (n *Node) sendPeer(p *Peer) {
	for {
		if !p.running {
			return
		}
		select {
		case <-p.ctx.Done():
			return
		case msgData, ok := <-p.outs:
			if !ok {
				return
			}
			err := n.p2pService.SendMessage(n.config.GetChainId(), p.Id, p2p.TOPIC_PEER_MESSAGE, msgData)
			if err != nil {
				glog.Error(err)
			} else {
				glog.Infof(">>> send message %s(%d) to %s(%s)", core.GetInfo(msgData), len(msgData), p.GetAddress(n).String(), p.Id)
			}
		}
	}
}

func (n *Node) syncPeer(p *Peer) {
	config := n.config
	for {
		if !p.running {
			return
		}
		if p.Key != nil {
			glog.Infoln("===", p.Id, util.GetString(p.GetAddress(n)), p.GetIndex(n))
		} else {
			glog.Infoln("===", p.Id)
		}
		for root, entry := range n.entrymap {
			e := n.getPeerEntry(p, entry.root)
			glog.Infof("--- @%s, %v(%v), %d, %d, %d, %s, %d, %s, %s", root, e.status, e.PeerStatus, e.BlockNumber, e.PeerCount, e.lastSendBlock, e.lastSendTime.Format("15:04:05.999"), e.lastRequestBlock, e.lastRequestTime.Format("15:04:05.999"), time.Unix(e.lastTime/1e9, e.lastTime%1e9).Format("15:04:05.999"))
		}
		time.Sleep(time.Duration(config.GetBlockDuration()) * time.Second)
	}
}

func (n *Node) dataPeer(p *Peer) {
	for {
		if !p.running {
			return
		}
		select {
		case <-p.ctx.Done():
			return
		case msgData, ok := <-p.dataChan:
			if !ok {
				return
			}
			err := n.p2pService.SendMessage(n.config.GetChainId(), p.Id, p2p.TOPIC_PEER_DATA, msgData)
			if err != nil {
				glog.Error(err)
			} else {
				glog.Infof(">>> send data %s(%d) to %s(%s)", core.GetInfo(msgData), len(msgData), p.GetAddress(n).String(), p.Id)
			}
		}
	}
}

func (n *Node) sendBlock(entry *Entry, p *Peer, blockNumber uint64) error {
	b, err := entry.merkle.GetBlockByIndex(blockNumber)
	if err != nil {
		return err
	}
	_, err = block.HashBlock(b)
	if err != nil {
		return err
	}
	blockData, err := b.MarshalBinary()
	if err != nil {
		return err
	}
	msgData, err := n.EncodeMessage(blockData)
	if err != nil {
		return err
	}
	if p.running {
		select {
		case <-p.ctx.Done():
			return nil
		default:
			p.dataChan <- msgData
			glog.Infof(">>> send data block %s(%d, %d) to %s(%s)", core.GetInfo(blockData), len(msgData), b.GetIndex(), p.GetAddress(n).String(), p.Id)
		}
	}
	return nil
}

func (n *Node) receivePeer(p *Peer) {
	for {
		if !p.running {
			return
		}
		select {
		case <-p.ctx.Done():
			return
		case data, ok := <-p.ins:
			if !ok {
				return
			}
			meta := core.GetMeta(data)
			switch meta {
			case core.CORE_BLOCK:
				b := &block.Block{}
				err := b.UnmarshalBinary(data)
				if err != nil {
					glog.Error(err)
				} else {
					n.receiveBlock(p, b)
				}

			default:
				glog.Errorln("<<< error message")
			}
		}
	}
}

func (n *Node) receiveRequest(p *Peer, r *pb.RequestInfo) {
	rootAccount, err := block.ByteToAddress(r.GetAccount())
	if err != nil {
		glog.Error(err)
	} else {
		entry, err := n.GetEntry(rootAccount)
		if err != nil {
			glog.Error(err)
		} else {
			entry.requestChan <- &requestEntry{
				p: p,
				r: r,
				t: time.Now().UnixNano(),
			}
		}
	}
}

func (n *Node) receiveBlock(p *Peer, b *block.Block) {
	h, err := block.HashBlock(b)
	if err != nil {
		glog.Error(err)
	} else {
		rootAccount := b.GetAccount()
		entry, err := n.GetEntry(rootAccount)
		if err != nil {
			glog.Error(err)
		} else {
			_, ok := entry.replyMap.Load(h.String())
			glog.Infof("<<< receive block @%s: %d, %d, %s <- %v, %v", util.GetString(rootAccount), entry.GetBlockNumber(), b.GetIndex(), h.String(), p.GetAddress(n), ok)
			if !ok {
				entry.replyMap.Store(h.String(), p)
				entry.replyMap.Store(fmt.Sprintf("%d", b.GetIndex()), b)
				entry.replyChan <- b
			} else {
				n.sendBlockReply(entry, b)
			}
		}
	}
}

func (n *Node) discoveryHandler(id string, msgData []byte) error {
	glog.Infof("[%s][%s] recv discovery from peer[%s], len: %d", n.config.GetChainId(), n.self.GetAddress(n), id, len(msgData))
	_, data, err := n.DecodeMessage(msgData)
	if err != nil {
		glog.Error(err)
	} else {
		meta, msg, err := core.Unmarshal(data)
		if err != nil {
			glog.Error(err)
		} else {
			if meta != core.CORE_PEER_INFO {
				err := util.ErrorOfInvalid("format", "peer info")
				glog.Error(err)
			} else {
				peerInfo := msg.(*pb.PeerInfo)
				p := n.AddPeer(id)
				n.UpdatePeer(p, peerInfo)
			}
		}
	}
	return nil
}

func (n *Node) GetIndex(address string) (uint64, error) {
	_, a, err := as.NewAccountFromAddress(address)
	if err != nil {
		return 0, err
	}
	data, err := a.MarshalBinary()
	if err != nil {
		return 0, err
	}
	m := new(big.Int).SetBytes(data)
	return m.Uint64(), nil
}

func (n *Node) messageHandler(id string, data []byte) error {
	glog.Infof("[%s][%s] recv message from peer[%s], len: %d", n.config.GetChainId(), n.self.GetAddress(n), id, len(data))
	fromPeer, data, err := n.DecodeMessage(data)
	if err != nil {
		glog.Error(err)
	} else {
		fromPeer.ins <- data
	}
	return nil
}

func (n *Node) dataHandler(id string, msgData []byte) error {
	glog.Infof("[%s][%s] recv data from peer[%s], len: %d", n.config.GetChainId(), n.self.GetAddress(n), id, len(msgData))
	fromPeer, data, err := n.DecodeMessage(msgData)
	if err != nil {
		glog.Error(err)
	} else {
		meta := core.GetMeta(data)
		if fromPeer != nil {
			switch meta {
			case core.CORE_REQUEST_INFO:
				_, msg, err := core.Unmarshal(data)
				if err != nil {
					glog.Error(err)
				} else {
					requestInfo := msg.(*pb.RequestInfo)
					n.receiveRequest(fromPeer, requestInfo)
				}
			case core.CORE_BLOCK:
				b := &block.Block{}
				err := b.UnmarshalBinary(data)
				if err != nil {
					glog.Error(err)
				} else {
					n.receiveBlock(fromPeer, b)
				}
			}
		}
	}
	return nil
}

func (n *Node) SendPeerInfo(rootAccount libcore.Address, toPeer *Peer) {
	rootData, err := block.AddressToByte(rootAccount)
	if err != nil {
		glog.Error(err)
	} else {
		pubKeyData, err := n.self.Key.MarshalBinary()
		if err != nil {
			glog.Error(err)
		} else {
			e := n.getPeerEntry(n.self, rootAccount)
			t := n.getPeerEntry(toPeer, rootAccount)
			glog.Infof("@%s:%v, %v, %v, %v, %v", util.GetString(rootAccount), toPeer.GetAddress(n), e.status, e.PeerStatus, t.status, t.PeerStatus)
			s := func(e *peerEntry, t *peerEntry) Status {
				if t.status > t.PeerStatus {
					return t.status
				}
				return t.PeerStatus
			}(e, t)
			peerData, err := core.Marshal(&pb.PeerInfo{
				Account:     rootData,
				PublicKey:   pubKeyData,
				BlockNumber: e.BlockNumber,
				PeerCount:   e.PeerCount,
				Status:      int64(s),
			})
			if err != nil {
				glog.Error(err)
			} else {
				msgData, err := n.EncodeMessage(peerData)
				if err != nil {
					glog.Error(err)
				} else {
					err := n.p2pService.SendMessage(n.config.GetChainId(), toPeer.Id, p2p.TOPIC_PEER_DISCOVERY, msgData)
					if err != nil {
						glog.Error(err)
					} else {
						glog.Infof(">>> send discovery %s(%d) to %s", core.GetInfo(peerData), len(msgData), toPeer.Id)
					}
				}
			}
		}
	}
}

func (n *Node) splitRootAndAccount(nameOrAddressAndRoot string) (string, libcore.Address, error) {
	list := strings.Split(nameOrAddressAndRoot, "@")
	switch len(list) {
	case 1:
		return list[0], nil, nil
	case 2:
		_, root, _ := as.NewAccountFromAddress(list[1])
		if root != nil {
			return list[0], root, nil
		}
		return "", nil, util.ErrorOfInvalid("root", list[1])
	default:
		return "", nil, util.ErrorOfInvalid("name", nameOrAddressAndRoot)
	}
}

func (n *Node) LoadPageByName(name string) (*zipfs.FileSystem, error) {
	if len(name) == 0 {
		return nil, util.ErrorOfInvalid("name", name)
	}

	accountName, root, err := n.splitRootAndAccount(name)
	if err != nil {
		return nil, err
	}
	_, account, _ := as.NewAccountFromAddress(accountName)
	if account != nil {
		return nil, util.ErrorOfInvalid("name", accountName)
	}
	entry, err := n.GetEntry(root)
	if err != nil {
		return nil, err
	}
	ss := entry.storage
	data, err := ss.ReadPageByName(accountName)
	if err != nil {
		return nil, err
	}
	reader := bytes.NewReader(data)
	fs, err := zipfs.NewFromReaderAt(reader, int64(len(data)), nil)
	if err != nil {
		return nil, err
	}
	return fs, nil
}

func (n *Node) LoadPageByNameOrAddress(nameOrAddress string) (*zipfs.FileSystem, error) {
	if len(nameOrAddress) == 0 {
		return nil, util.ErrorOfInvalid("name", nameOrAddress)
	}

	accountNameOrAddress, root, err := n.splitRootAndAccount(nameOrAddress)
	if err != nil {
		return nil, err
	}
	entry, err := n.GetEntry(root)
	if err != nil {
		return nil, err
	}
	ss := entry.storage

	var data []byte
	_, account, err := as.NewAccountFromAddress(accountNameOrAddress)
	if err != nil {
		data, err = ss.ReadPageByName(accountNameOrAddress)
		if err != nil {
			return nil, err
		}
	} else {
		data, err = ss.ReadPageByAddress(account)
		if err != nil {
			return nil, err
		}
	}
	reader := bytes.NewReader(data)
	fs, err := zipfs.NewFromReaderAt(reader, int64(len(data)), nil)
	if err != nil {
		return nil, err
	}
	return fs, nil
}

func (n *Node) LoadPageByAddress(address string) (*zipfs.FileSystem, error) {
	accountAddress, root, err := n.splitRootAndAccount(address)
	if err != nil {
		return nil, err
	}
	_, account, err := as.NewAccountFromAddress(accountAddress)
	if err != nil {
		return nil, err
	}
	entry, err := n.GetEntry(root)
	if err != nil {
		return nil, err
	}
	ss := entry.storage

	data, err := ss.ReadPageByAddress(account)
	if err != nil {
		return nil, err
	}
	reader := bytes.NewReader(data)
	fs, err := zipfs.NewFromReaderAt(reader, int64(len(data)), nil)
	if err != nil {
		return nil, err
	}
	return fs, nil
}

func (n *Node) LoadServiceByNameOrAddress(nameOrAddress string) (*zipfs.FileSystem, error) {
	if len(nameOrAddress) == 0 {
		return nil, util.ErrorOfInvalid("name", nameOrAddress)
	}

	accountNameOrAddress, root, err := n.splitRootAndAccount(nameOrAddress)
	if err != nil {
		return nil, err
	}
	entry, err := n.GetEntry(root)
	if err != nil {
		return nil, err
	}
	ss := entry.storage

	var data []byte
	_, account, err := as.NewAccountFromAddress(accountNameOrAddress)
	if err != nil {
		data, err = ss.ReadPageByName(accountNameOrAddress)
		if err != nil {
			return nil, err
		}
	} else {
		data, err = ss.ReadPageByAddress(account)
		if err != nil {
			return nil, err
		}
	}
	reader := bytes.NewReader(data)
	fs, err := zipfs.NewFromReaderAt(reader, int64(len(data)), nil)
	if err != nil {
		return nil, err
	}
	return fs, nil
}

func (n *Node) InitP2P(p2pService libp2p.P2PService) error {
	n.p2pService = p2pService
	return nil
}

func (n *Node) start() error {
	cbm := make(map[string]libp2p.MessageCallback)
	cbm[p2p.TOPIC_PEER_DISCOVERY] = n.discoveryHandler
	cbm[p2p.TOPIC_PEER_MESSAGE] = n.messageHandler
	cbm[p2p.TOPIC_PEER_DATA] = n.dataHandler
	err := n.p2pService.Start(n.config, cbm)
	if err != nil {
		return err
	}

	n.self.Id = n.config.GetNodeId()
	return nil
}

func (n *Node) Start() error {
	if err := n.start(); err != nil {
		return err
	}

	go n.connect()
	go n.generate()
	go n.discovery()

	return nil
}

func (n *Node) Close() error {
	for _, entry := range n.entrymap {
		if entry.merkle != nil {
			if err := entry.merkle.Close(); err != nil {
				return err
			}
		}
		if entry.storage != nil {
			if err := entry.storage.Close(); err != nil {
				return err
			}
		}
	}
	if n.p2pService != nil {
		if err := n.p2pService.Stop(); err != nil {
			return err
		}
	}
	return nil
}

func (n *Node) discovery() {
	for {
		util.Sleep(
			time.Second,
			time.Duration(n.config.GetBlockDuration())*time.Second,
			n._peerChanged,
			n._peerUpdated,
		)
	}
}

func (n *Node) _peerUpdated(_ []interface{}) {
	//ReVerifyTrustRoots
	err := n.p2pService.VerifyPeers(n.config.GetChainId())
	if err != nil {
		glog.Error(err)
	}
}

func (n *Node) _peerChanged(_ []interface{}) bool {
	peerChanged := false
	peers, err := n.p2pService.ListPeers(n.config.GetChainId())
	if err != nil {
		glog.Error(err)
	} else {
		localPeerMap := make(map[string]struct{})
		for _, p := range n.idmap {
			localPeerMap[p.Id] = struct{}{}
		}
		netPeerMap := make(map[string]struct{})
		for _, pid := range peers {
			if pid != n.self.Id {
				netPeerMap[pid] = struct{}{}
				_, ok := localPeerMap[pid]
				if !ok {
					peerChanged = peerChanged || true
					n.AddPeer(pid)
				}
			}
		}
		for _, p := range n.idmap {
			_, ok := netPeerMap[p.Id]
			if !ok {
				peerChanged = peerChanged || true
				n.RemovePeer(p)
			}
		}
	}
	return peerChanged
}

func (n *Node) GetNodeKey() libaccount.Key {
	return n.key
}

func (n *Node) GetPeer(index uint64) *Peer {
	n.peerLocker.Lock()
	defer n.peerLocker.Unlock()

	return n.indexmap[index]
}

func (n *Node) AddPeer(id string) *Peer {
	n.peerLocker.Lock()
	defer n.peerLocker.Unlock()

	p, ok := n.idmap[id]
	if !ok {
		ctx, cancel := context.WithCancel(context.Background())
		p = &Peer{
			Id: id,

			running: true,
			ctx:     ctx,
			cancel:  cancel,

			ins:      make(chan []byte, 32),
			outs:     make(chan []byte, 32),
			dataChan: make(chan []byte, 32),

			peerMap:    &sync.Map{},
			peermap:    make(map[string]*peerEntry),
			peerLocker: &sync.RWMutex{},
		}
		glog.Infof("=== add peer: %s", id)
		n.idmap[id] = p

		go n.syncPeer(p)
		go n.dataPeer(p)
		go n.sendPeer(p)
		go n.receivePeer(p)
	}
	return p
}

func (n *Node) RemovePeer(p *Peer) {
	n.peerLocker.Lock()
	defer n.peerLocker.Unlock()

	p.running = false
	for _, e := range p.peermap {
		e.running = false
	}
	p.cancel()
	glog.Infof("=== remove peer: %s, %s, %d", p.Id, util.GetString(p.GetAddress(n)), p.GetIndex(n))

	delete(n.indexmap, p.GetIndex(n))
	delete(n.idmap, p.Id)

	time.Sleep(100 * time.Millisecond)
	close(p.ins)
	close(p.outs)
	close(p.dataChan)
}

func (n *Node) UpdatePeer(p *Peer, info *pb.PeerInfo) error {
	n.peerLocker.Lock()
	defer n.peerLocker.Unlock()

	rootAccount, err := block.ByteToAddress(info.Account)
	if err != nil {
		return err
	}
	e := n.getPeerEntry(p, rootAccount)
	e.BlockNumber = info.BlockNumber
	e.PeerCount = info.PeerCount
	if info.Status > int64(e.PeerStatus) {
		e.PeerStatus = Status(info.Status)
		glog.Infof("=== update peer @%s: %s, %v, %d, %v, %v", util.GetString(rootAccount), p.Id, p.GetAddress(n), p.GetIndex(n), e.status, e.PeerStatus)
	} else {
		e.infoCount++
	}
	if p.Key == nil && len(info.PublicKey) > 0 {
		_, publicKey, err := as.NewPublicFromBytes(info.PublicKey)
		if err != nil {
			return err
		}
		p.Key = publicKey
		address, err := publicKey.GenerateAddress()
		if err != nil {
			return err
		} else {
			index, err := n.GetIndex(address.String())
			if err != nil {
				return err
			} else {
				n.indexmap[index] = p
			}
		}
		e.status = PeerKnown
		glog.Infof("=== update peer @%s: %s, %v, %d, %v, %v", util.GetString(rootAccount), p.Id, p.GetAddress(n), p.GetIndex(n), e.status, e.PeerStatus)
	} else {
		if e.status < PeerKnown && len(info.PublicKey) > 0 {
			_, publicKey, err := as.NewPublicFromBytes(info.PublicKey)
			if err != nil {
				return err
			}
			address, err := publicKey.GenerateAddress()
			if err != nil {
				return err
			} else {
				index, err := n.GetIndex(address.String())
				if err != nil {
					return err
				} else {
					if p.index == index {
						e.status = PeerKnown
						glog.Infof("=== update peer @%s: %s, %v, %d, %v, %v", util.GetString(rootAccount), p.Id, p.GetAddress(n), p.GetIndex(n), e.status, e.PeerStatus)
					}
				}
			}
		}
	}
	if e.infoCount > 3 {
		e.infoCount = 0
		n.SendPeerInfo(rootAccount, p)
	}
	return nil
}

func (n *Node) ListPeers() []*Peer {
	n.peerLocker.RLock()
	defer n.peerLocker.RUnlock()

	list := make([]*Peer, 0)
	for _, p := range n.idmap {
		list = append(list, p)
	}
	return list
}

func (n *Node) ListPeersBy(rootAccount libcore.Address) []*Peer {
	n.peerLocker.RLock()
	defer n.peerLocker.RUnlock()

	root := util.GetString(rootAccount)
	list := make([]*Peer, 0)
	for _, p := range n.idmap {
		_, ok := p.peermap[root]
		if ok {
			list = append(list, p)
		}
	}
	return list
}

func (n *Node) EncodeMessage(d []byte) ([]byte, error) {
	m := &pb.Message{
		Id:        n.newId(),
		Data:      d,
		Node:      n.self.GetIndex(n),
		Signature: nil,
	}
	msgData, err := core.Marshal(m)
	if err != nil {
		return nil, err
	}
	h, err := cs.Hash(msgData)
	if err != nil {
		return nil, err
	}
	signature, err := n.key.Sign(h, msgData)
	if err != nil {
		return nil, err
	}
	m.Signature = signature

	data, err := core.Marshal(m)
	if err != nil {
		return nil, err
	}
	glog.Infof(">>> send peer %s(%d, %d)", core.GetInfo(d), m.Id, len(data))
	return data, nil
}

func (n *Node) DecodeMessage(d []byte) (*Peer, []byte, error) {
	meta, m, err := core.Unmarshal(d)
	if err != nil {
		return nil, nil, err
	}
	if meta != core.CORE_MESSAGE {
		return nil, nil, util.ErrorOfInvalid("format", "message")
	}
	msg := m.(*pb.Message)

	fromIndex := msg.GetNode()
	data := msg.GetData()
	t := core.GetInfo(d)
	fromPeer := n.GetPeer(fromIndex)
	if fromPeer != nil {
		err := n.VerifyMessage(fromPeer.Key, msg)
		if err != nil {
			return nil, nil, err
		}
		glog.Infof("<<< receive peer %s %d(%s) from %s(%s)", t, msg.Id, core.GetInfo(data), fromPeer.GetAddress(n), fromPeer.Id)
		return fromPeer, data, nil
	} else if fromIndex == n.self.GetIndex(n) {
		glog.Infof("<<< receive self %s %d(%s) from %s(%s)", t, msg.Id, core.GetInfo(data), n.self.GetAddress(n), n.self.Id)
		return n.self, data, nil
	} else {
		meta := core.GetMeta(data)
		if meta == core.CORE_PEER_INFO {
			_, cmsg, err := core.Unmarshal(data)
			if err != nil {
				return nil, nil, err
			}
			peerInfo := cmsg.(*pb.PeerInfo)
			_, publicKey, err := as.NewPublicFromBytes(peerInfo.PublicKey)
			if err != nil {
				return nil, nil, err
			}
			err = n.VerifyMessage(publicKey, msg)
			if err != nil {
				return nil, nil, err
			}
			address, err := publicKey.GenerateAddress()
			if err != nil {
				return nil, nil, err
			}
			index, err := n.GetIndex(address.String())
			if err != nil {
				return nil, nil, err
			}
			glog.Infof("<<< receive peer info %s %d(%s) from %s(%d)", t, msg.Id, core.GetInfo(data), address, index)
			return nil, data, nil
		} else {
			glog.Infof("<<< receive unknown %s %d(%s) from %d(%s)", t, msg.Id, core.GetInfo(data), fromIndex, n.self.Id)
			return nil, nil, util.ErrorOfUnknown("peer", "data")
		}
	}
}

func (n *Node) VerifyMessage(pk libaccount.PublicKey, msg *pb.Message) error {
	signature := msg.Signature
	msg.Signature = nil
	defer func() {
		msg.Signature = signature
	}()
	msgData, err := core.Marshal(msg)
	if err != nil {
		return err
	}
	h, err := cs.Hash(msgData)
	if err != nil {
		return err
	}
	ok, err := pk.Verify(h, msgData, signature)
	if err != nil {
		return err
	}
	if !ok {
		return util.ErrorOfInvalid("signature", "message")
	}
	return nil
}
